package com.asset.dispoal.business.bsEvidenceRecognition.service.commom;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.entity.BsRecognitionAllRecord;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.entity.BsRecognitionRecord;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.entity.BsRecognitionRecordMapping;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.entity.EvidenceRecognition;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.mapper.BsRecognitionAllRecordMapper;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.mapper.BsRecognitionRecordMapper;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.mapper.BsRecognitionRecordMappingMapper;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.db.mapper.BusinessDataManageMapper;
import com.asset.dispoal.business.bsEvidenceRecognition.domain.redis.dto.RedisMatchDTO;
import com.asset.dispoal.business.bsEvidenceRecognition.dto.EvidenceMatchRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import tech.mhuang.pacebox.core.date.DateTimeUtil;
import tech.mhuang.pacebox.core.ddd.BaseCommand;
import tech.mhuang.pacebox.core.exception.BusinessException;
import tech.mhuang.pacebox.core.id.BaseIdeable;
import tech.mhuang.pacebox.core.page.PageParam;
import tech.mhuang.pacebox.core.page.PageUtil;
import tech.mhuang.pacebox.core.util.CollectionUtil;
import tech.mhuang.pacebox.springboot.core.entity.RequestModel;
import tech.mhuang.pacebox.springboot.core.local.GlobalHeaderThreadLocal;
import tech.mhuang.pacebox.springboot.core.rest.SingleRestTemplate;
import tech.mhuang.pacebox.springboot.protocol.Result;
import tech.mhuang.pacebox.springboot.redis.commands.IRedisExtCommands;

import java.net.InetAddress;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author qr
 * @date 2022/5/10$
 */
@Component
public class EvidenceMatchCommand implements BaseCommand<EvidenceMatchRequest, Result> {

    @Autowired
    BusinessDataManageMapper businessDataManageMapper;

    @Autowired
    BsRecognitionAllRecordMapper bsRecognitionAllRecordMapper;

    @Autowired
    BsRecognitionRecordMapper bsRecognitionRecordMapper;

    @Autowired
    BaseIdeable<String> snowFlak;

    @Autowired
    BsRecognitionRecordMappingMapper bsRecognitionRecordMappingMapper;

    @Autowired
    private IRedisExtCommands redisExtCommands;

    @Autowired
    private RedisProperties redisProperties;

    @Autowired
    private SingleRestTemplate singleRestTemplate;

    @Autowired
    private Environment environment;

    @Override
    @Transactional
    public Result execute(EvidenceMatchRequest evidenceMatchRequest) {

        //批次下所有未识别  识别失败证据
        List<EvidenceRecognition> evidenceRecognitions = businessDataManageMapper.queryEvidence(evidenceMatchRequest);
        if (CollectionUtil.isEmpty(evidenceRecognitions)) {
            return Result.faild("暂无可识别的证据");
        }
        businessDataManageMapper.batchMatching(evidenceRecognitions.stream().map(EvidenceRecognition::getId).collect(Collectors.toList()));
        evidenceMatchRequest.setUserId(GlobalHeaderThreadLocal.get().getUserId());
        List<Map<String, Object>> recognitionData = new ArrayList<>();
        final List<Map<String, Object>> data = getData(evidenceRecognitions, recognitionData);
        String allRecognitionRecord = saveAllRecognitionRecord(evidenceMatchRequest);
        List<List<Map<String, Object>>> lists = subListPush(data);

        List<Map<String, String>> mapList = businessDataManageMapper.queryDataDetail(evidenceMatchRequest.getAssetInstBatchId());

        List<Map<String, Object>> queryResult = businessDataManageMapper.queryResult(evidenceMatchRequest.getAssetInstBatchId(), mapList);
        List<RedisMatchDTO> dtos = new ArrayList<>();
        lists.forEach(item -> dtos.add(saveRecognitionData(evidenceMatchRequest, item, queryResult, allRecognitionRecord)));

        sendData(dtos, environment.getProperty("evidence_" + evidenceMatchRequest.getIsExpedited() + "_url"));
        return Result.ok();
    }


    private String saveAllRecognitionRecord(EvidenceMatchRequest evidenceMatchRequest) {
        final String id = snowFlak.generateId();
        BsRecognitionAllRecord bsRecognitionRecordDO = new BsRecognitionAllRecord();
        bsRecognitionRecordDO.setCreateUser(evidenceMatchRequest.getUserId());
        bsRecognitionRecordDO.setCreateTime(DateTimeUtil.currentDate());
        bsRecognitionRecordDO.setId(id);
        bsRecognitionRecordDO.setIsMatchRecognition(evidenceMatchRequest.getIsMatchRecognition());
        bsRecognitionRecordDO.setMatchName(evidenceMatchRequest.getMatchName());
        bsRecognitionRecordDO.setAssetInstBatchId(evidenceMatchRequest.getAssetInstBatchId());
        bsRecognitionRecordDO.setIsExpedited(evidenceMatchRequest.getIsExpedited());
        bsRecognitionRecordDO.setRecognitionStatus("2");
        bsRecognitionRecordDO.setMatchType(evidenceMatchRequest.getMatchType());
        bsRecognitionAllRecordMapper.insert(bsRecognitionRecordDO);
        return id;
    }


    private <T> List<List<T>> subListPush(List<T> dataList) {
        List<PageParam> subPageList = new ArrayList<>(3);
        PageParam subPage1 = new PageParam(10000, 1, 1000);
        PageParam subPage2 = new PageParam(1000, 2, 10);
        subPageList.add(subPage1);
        subPageList.add(subPage2);
        return PageUtil.subList(dataList, subPageList);
    }


    /**
     * python数据封装
     *
     * @param list
     * @return
     */
    private List<Map<String, Object>> getData(List<EvidenceRecognition> list, List<Map<String, Object>> recognitionData) {
        Map<String, List<EvidenceRecognition>> collect = list.stream().collect(Collectors.groupingBy(EvidenceRecognition::getFilepath));
        for (String key : collect.keySet()) {
            List<EvidenceRecognition> evidenceRecognitions = collect.get(key);
            Map<String, Object> map = new HashMap<>();
            map.put("actionWay", evidenceRecognitions.get(0).getActionWay().toString());
            map.put("actionKey", evidenceRecognitions.get(0).getActionKey());
            map.put("evidenceItemId", evidenceRecognitions.get(0).getEvidenceTypeId());
            map.put("cognateOthers", Optional.of(evidenceRecognitions.get(0).getCognateOthers().toString()).orElse(null));
            map.put("cognateOthersType", evidenceRecognitions.get(0).getCognateOthersType());
            map.put("cognateOthersId", evidenceRecognitions.get(0).getCognateOthersId());
            map.put("mobileName", Optional.ofNullable(evidenceRecognitions.get(0).getMobileName()).orElse("chinese_ocr_db_crnn_mobile"));
            map.put("x", evidenceRecognitions.get(0).getX());
            map.put("y", evidenceRecognitions.get(0).getY());
            List<Map<String, Object>> allList = new ArrayList<>();
            List<Map<String, String>> mapList = new ArrayList<>();
            Map<String, Object> dirMap = new HashMap<>();
            evidenceRecognitions.forEach(item -> {
                Map<String, String> sunMap = new HashMap<>(2);
                sunMap.put("id", item.getId());
                sunMap.put("filepath", item.getReplaceFileName());
                mapList.add(sunMap);
            });
            dirMap.put("files", mapList);
            dirMap.put("dirPath", environment.getProperty("file.evidence.url") + "/" + evidenceRecognitions.get(0).getFilepath());
            allList.add(dirMap);
            map.put("cognateFiles", allList);
            recognitionData.add(map);
        }
        return recognitionData;
    }

    private RedisMatchDTO saveRecognitionData(EvidenceMatchRequest evidenceMatchRequest, List<Map<String, Object>> data, List<Map<String, Object>> maps, String allRecordId) {
        String ts = snowFlak.generateId();
        //存储数据到识别记录表
        BsRecognitionRecord bsRecognitionRecord = new BsRecognitionRecord();
        bsRecognitionRecord.setId(snowFlak.generateId());
        bsRecognitionRecord.setEvidenceBatchId(ts);
        bsRecognitionRecord.setAssetInstBatchId(evidenceMatchRequest.getAssetInstBatchId());
        bsRecognitionRecord.setRecognitionStatus("2");
        bsRecognitionRecord.setCreateUser(evidenceMatchRequest.getUserId());
        bsRecognitionRecord.setCreateTime(Date.from(Instant.now()));
        bsRecognitionRecord.setOperateUser(evidenceMatchRequest.getUserId());
        bsRecognitionRecord.setOperateTime(Date.from(Instant.now()));
        bsRecognitionRecord.setIsExpedited(evidenceMatchRequest.getIsExpedited());
        bsRecognitionRecord.setAllRecordId(allRecordId);
        bsRecognitionRecordMapper.insert(bsRecognitionRecord);
        //存储数据到识别记录映射表
        List<BsRecognitionRecordMapping> recordMappingList = new ArrayList<>();
        for (Map<String, Object> stringObjectMap : data) {
            List<Map<String, Object>> files = (List<Map<String, Object>>) stringObjectMap.get("cognateFiles");
            for (Map<String, Object> fileMap : files) {
                List<Map<String, Object>> fileList = (List<Map<String, Object>>) fileMap.get("files");
                for (Map<String, Object> evidenceFileMap : fileList) {
                    BsRecognitionRecordMapping bsRecognitionRecordMapping = new BsRecognitionRecordMapping();
                    bsRecognitionRecordMapping.setId(snowFlak.generateId());
                    bsRecognitionRecordMapping.setCreateTime(DateTimeUtil.currentDate());
                    bsRecognitionRecordMapping.setCreateUser(evidenceMatchRequest.getUserId());
                    bsRecognitionRecordMapping.setEvidenceBatchId(ts);
                    bsRecognitionRecordMapping.setEvidenceId((String) evidenceFileMap.get("id"));
                    recordMappingList.add(bsRecognitionRecordMapping);
                }
            }

        }
        bsRecognitionRecordMappingMapper.saveBatch(recordMappingList);

        redisExtCommands.hset(6, "ocr_data", ts + "_" + evidenceMatchRequest.getIsExpedited(), JSON.toJSONString(maps, JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.LargeObject));
        redisExtCommands.hset(6, "ocr_before", ts + "_" + evidenceMatchRequest.getIsExpedited(), data);
        RedisMatchDTO dto = new RedisMatchDTO();
        dto.setDb("6");
        dto.setId("1");
        dto.setKey(ts + "_" + evidenceMatchRequest.getIsExpedited());
        dto.setHost(redisProperties.getHost());
        dto.setPort(redisProperties.getPort());
        dto.setPasswd(redisProperties.getPassword());
        dto.setOcrFile("ocr_before");
        dto.setOcrData("ocr_data");
        dto.setErrorKey("err_key");
        dto.setNotifyKey("notify_key");
        try {
            dto.setServerUrl("http://" + InetAddress.getLocalHost().getHostAddress() + ":8014" + "/business/bsEvidenceRecognition/PythonCallback");
        } catch (Exception e) {
            throw new BusinessException(e);
        }
        return dto;
    }


    private void sendData(List<RedisMatchDTO> redisDTOS, String url) {
        redisDTOS.forEach(item -> {
            RequestModel<String> requestModel = new RequestModel<String>() {
            };
            requestModel.setUrl(url);
            requestModel.setMethod(HttpMethod.POST);
            requestModel.setSufUrl("/file/documentRecognition");
            requestModel.setParams(JSON.toJSON(item));
            singleRestTemplate.request(requestModel);
        });
    }


}
